/*
	Copyright (C) 2008 by Jean-François Geyelin
	jfgeyelin@gmail.com

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the
	Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/


#include "all.h"
#include "structures.h"
#include "ReplayHandler.h"
#include "SurfaceHandler.h"
#include "globals.h"
#include "Map.h"
#include "GameModifier.h"
#include "safeFileIO.h"
#include "getSeedFromServer.h"
#include "handleEvents.h"
#include "pauseMenu.h"
#include "youLostMenu.h"
#include "submitMenu.h"
#include "postFile.h"
#include "readMap.h"

bool playMap(std::string mapName, PlayerImportantInformations * pii, const char *replayPath, bool record) {

    TEST_EXECUTION()
    bool replay = replayPath!=NULL;


    int seed = rand();

    ReplayHandler replayHandler;
    RLEHandler rleHandler;//used for decompressing a replay, and recording one.


    if (record) {
        if (!getSeedFromServer(&seed)) {//no internet connection => no competition!
            return false;
        }
    }

    TEST_EXECUTION()

    SurfaceHandler::colorScreen(255,255,255);

    if (replay) {
        TEST_EXECUTION()
        replayHandler.readTempFile(replayPath);
        TEST_EXECUTION()
        mapName = replayHandler.getMapName();
        seed = replayHandler.getSeed();
    }

    myRandomMaker->seed(seed);


    TEST_EXECUTION()
    map = new Map(mapName);
    TEST_EXECUTION()
    camera = new Camera();

    Uint32 lastFrameMS = 0;

    if (replay || record) {
        player->setNumberOfLives(3);
        player->setNumberOfCoins(0);
        player->setNumberOfPoints(0);
        player->setHasSpear(true);
        player->setHasShield(true);
    }
    else
    {
        player->setNumberOfLives(pii->numberOfLives);
        player->setNumberOfCoins(pii->numberOfCoins);
        player->setNumberOfPoints(pii->numberOfPoints);
        player->setHasSpear(pii->hasSpear);
        player->setHasShield(pii->hasShield);
    }

    if (replay) {
        size_t unusedVar;
        rleHandler.startReadingData(replayHandler.getData(&unusedVar));//initialise the rleHandler
        //so that it knows where the data it must decompress is.

    }




    TEST_EXECUTION()
	ios = new InfoOnScreen();
	if (replay) {
        ios->nickName = replayHandler.getNickName();
        ios->replayNumber = replayHandler.getSeed();
	}
	TEST_EXECUTION()
    keyPressed = new KeyPressed();


    int time=5000;
    if (replay || record) {
        time = 4000;
    }
    time+=1000;
   // time = 50;





    SDL_Surface *temporaryBuffer = SDL_CreateRGBSurface(SDL_HWSURFACE, screenSurface->w, screenSurface->h, 32, bmask, gmask, rmask, amask);
    SDL_Surface *temporarySurfaceForZoom = SDL_CreateRGBSurface(SDL_HWSURFACE, screenSurface->w, screenSurface->h, 32, bmask, gmask, rmask, amask);

    zoomFactor = 1;

    inReplayMode = replay;
    TEST_EXECUTION()
    GameModifier::executeAllModifications();
    TEST_EXECUTION()
    GameModifier::deleteAllModifications();
    TEST_EXECUTION()

    int i=0;

   	while (player->hasFinishedLevel==false) {
		handleEvents();
        if (replay) {
            keyPressed->setKeys(rleHandler.readNextByte());
        }
        else {
            keyPressed->readKeys();

            if (record)
            rleHandler.addByte(keyPressed->getByte());
        }


        TEST_EXECUTION()
		objectList->animate();
        TEST_EXECUTION()


        #ifndef NO_SCREEN
        while ((SDL_GetTicks() - lastFrameMS) < 30) {
            SDL_Delay(1);
        }
        lastFrameMS = SDL_GetTicks();
        #endif

		handleEvents();
        if (replay) {
            keyPressed->setKeys(rleHandler.readNextByte());
        }
        else {
            keyPressed->readKeys();
            if (record)
            rleHandler.addByte(keyPressed->getByte());
        }




        if (keyPressed->plus)
        zoomFactor+=0.05;


        if (keyPressed->minus)
        zoomFactor-=0.05;


        TEST_EXECUTION()
        if (!player->isInSlowMotion()) {
            objectList->animate();
        }
        TEST_EXECUTION()

        if (zoomFactor != 1) {
            TEST_EXECUTION()

            if (zoomFactor<1)//for safety
            zoomFactor = 1;

            SDL_Surface *realScreenSurface = screenSurface;
            screenSurface = temporaryBuffer;
            int real_SCREEN_WIDTH = SCREEN_WIDTH;
            int real_SCREEN_HEIGHT = SCREEN_HEIGHT;
            SCREEN_WIDTH = (int)(SCREEN_WIDTH/zoomFactor);
            SCREEN_HEIGHT = (int)(SCREEN_HEIGHT/zoomFactor);
            map->moveCamera((int)player->getX(),(int)player->getY());
            #ifndef NO_SCREEN
            map->draw();
            #endif
            objectList->draw();
            #ifndef NO_SCREEN
            SCREEN_WIDTH = real_SCREEN_WIDTH;
            SCREEN_HEIGHT = real_SCREEN_HEIGHT;
            screenSurface = realScreenSurface;
            SurfaceHandler::SDL_BlitSurface( temporaryBuffer,NULL,temporarySurfaceForZoom, NULL );
            my_sge_transform(temporarySurfaceForZoom, screenSurface, 0, zoomFactor,  zoomFactor, 0,0,(int)(screenSurface->w*zoomFactor/2),(int)(screenSurface->h*zoomFactor/2), SGE_TTMAP);
            #endif
        }
        else
        {
            map->moveCamera((int)player->getX(),(int)player->getY());
            #ifndef NO_SCREEN
            map->draw();
            #endif
            objectList->draw();
        }

        #ifndef NO_SCREEN
		ios->draw(time);

        SDL_Flip( screenSurface );
        #endif

        i++;
        if (!ios->timeMustBeStopped) {
            if (!player->isInSlowMotion() || i&1)
            time-=1;
        }
        if (time<0 || player->getNumberOfLives()<0) {
            player->setNumberOfPoints(0);
            player->hasFinishedLevel = true;
        }

		if (quit) {
		    TEST_EXECUTION()
            allSounds->play("pause");
			pauseMenu();
			TEST_EXECUTION()
			if (quit) {
			    TEST_EXECUTION()
                delete ios;
                delete camera;
                delete map;
                TEST_EXECUTION()
                SDL_FreeSurface(temporaryBuffer);
                SDL_FreeSurface(temporarySurfaceForZoom);
                TEST_EXECUTION()

#ifndef NO_MUSIC
                musicThread->smoothlyStartPlayingMusic(MENU_MUSIC);
                TEST_EXECUTION()
#endif

                return false;
			}
			quit = false;

            SDL_FreeSurface(temporaryBuffer);
            SDL_FreeSurface(temporarySurfaceForZoom);

            temporaryBuffer = SDL_CreateRGBSurface(SDL_HWSURFACE, screenSurface->w, screenSurface->h, 32, bmask, gmask, rmask, amask);
            temporarySurfaceForZoom = SDL_CreateRGBSurface(SDL_HWSURFACE, screenSurface->w, screenSurface->h, 32, bmask, gmask, rmask, amask);

		}
	}
	time++;

    bool playerLost = false;
    if (time==0 && !replay) {
        youLostMenu("Out of time!");
        playerLost = true;
    }

    if (player->getNumberOfLives()<0 && !replay) {
        youLostMenu("Out of lives!");
        playerLost = true;
    }

    //time = 0;

    if (record && !playerLost) {
        if (submitScoreMenu(player->getNumberOfPoints(),time,seed)) {
            TEST_EXECUTION()
            replayHandler.writeTempFile(seed,mapName,rleHandler);
            postFileToServer();
            TEST_EXECUTION()
        }
    }

    if (!replay && !record && !playerLost) {
        pii->numberOfLives = player->getNumberOfLives();
        pii->numberOfCoins = player->getNumberOfCoins();
        pii->hasSpear = player->getHasSpear();
        pii->numberOfPoints = player->getNumberOfPoints();
        pii->hasShield = player->getHasShield();
    }
    else
    {
        TEST_EXECUTION()
        #ifdef linux
        if (replay) {
            FILE *tempFile = fopen_safe("replay_results.txt","w");
            fprintf(tempFile,"seed,%i\n",seed);
            fprintf(tempFile,"score,%i\n",player->getNumberOfPoints()+time);
            fprintf(tempFile,"time,%i\n",time);
            fprintf(tempFile,"nick_name,%s\n",replayHandler.getNickName().c_str());
            fprintf(tempFile,"map_number,%i\n",getMapNumberFromName(mapName));
            fclose(tempFile);
        }
        #endif
    }


	bool returnValue = player->hasFinishedLevel && !playerLost ;

    TEST_EXECUTION()
    SDL_FreeSurface(temporaryBuffer);
    SDL_FreeSurface(temporarySurfaceForZoom);
    TEST_EXECUTION()
	delete ios;     //WARNING: you also have to call the destructors in the previous while
	TEST_EXECUTION()
	delete camera;
	TEST_EXECUTION()
	delete map;
    TEST_EXECUTION()
#ifndef NO_MUSIC
    musicThread->smoothlyStartPlayingMusic(MENU_MUSIC);
#endif
    TEST_EXECUTION()
	return returnValue;
}
